/*
 * SPDX-License-Identifier: MIT
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 * Description: define crypto module
 * Create: 2024-07-09
 */

#ifndef CRYPTO_H
#define CRYPTO_H

#include <stdint.h>
#include <stdbool.h>

#ifndef __cplusplus
#include <stdatomic.h>
#else
#include <atomic>
using namespace std;
#endif

#include "openssl/ssl.h"
#include "urpc_framework_types.h"

#ifdef __cplusplus
extern "C" {
#endif

#define URPC_MAX_CIPHER_LIST_LENGTH                 4096
#define URPC_CRYPTO_KEY_BYTES                       32
#define URPC_AES_CHECK_LEN                          (URPC_AES_IV_LEN + URPC_AES_TAG_LEN)

// crypto_key generated by server for data plane.
typedef struct crypto_key {
    uint8_t key[URPC_CRYPTO_KEY_BYTES];
} __attribute__((packed)) crypto_key_t;

typedef struct urpc_cipher {
    const EVP_CIPHER *cipher;                       // generated cipher object
    crypto_key_t crypto_key;                        // key for encrypt/decrypt, security random number
    uint32_t chid;                                  // local channel id, used as the fixed field for iv
    atomic_ullong counter;                          // counter for iv, used as the variable field for iv
} urpc_cipher_t;

SSL *crypto_ssl_init(int sockfd, bool is_server);

void crypto_ssl_uninit(SSL *ssl);

// Send data by SSL connection, return the actual size of successfully sent data on success.
size_t crypto_ssl_send(SSL *ssl, void *buf, size_t size);

static inline ssize_t crypto_ssl_send_async(SSL *ssl, void *buf, size_t size)
{
    /* non blocking send */
    return SSL_write(ssl, buf, size);
}

// Receive data from SSL connection, return the actual size of successfully received data.
size_t crypto_ssl_recv(SSL *ssl, void *buf, size_t size);

static inline ssize_t crypto_ssl_recv_async(SSL *ssl, void *buf, size_t size)
{
    /* non blocking recv */
    return SSL_read(ssl, buf, size);
}

bool crypto_is_ssl_enabled(void);

bool crypto_is_ssl_enabled_lock_free(void);

bool crypto_is_dp_ssl_enabled(void);

bool crypto_is_dp_ssl_enabled_lock_free(void);

int crypto_ssl_gen_crypto_key(crypto_key_t *crypto_key);

uint32_t crypto_gen_rand_channel_id(uint32_t id);

int crypto_cipher_init(urpc_cipher_t *cipher_opt, crypto_key_t *crypto_key);

void crypto_cipher_uninit(urpc_cipher_t *cipher_opt);

EVP_CIPHER_CTX *crypto_encrypt_ctx_init(urpc_cipher_t *cipher_opt, unsigned char *iv, size_t iv_len);

int crypto_encrypt_user_data(
    EVP_CIPHER_CTX *ctx, urpc_sge_t *sge, uint32_t sge_num, uint32_t hdr_index, uint32_t first_sge_offset);

int crypto_decrypt_user_data(
    EVP_CIPHER_CTX *ctx, urpc_sge_t *sge, uint32_t sge_num, uint32_t hdr_index, uint32_t first_sge_offset);

int crypto_encrypt_keepalive_req(urpc_cipher_t *cipher_opt, urpc_sge_t *sge, uint32_t sge_num);

int crypto_decrypt_keepalive_req(urpc_cipher_t *cipher_opt, urpc_sge_t *sge, uint32_t sge_num);

int crypto_server_cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint32_t server_channel, unsigned char *iv, size_t iv_len);

uint32_t crypto_security_field_size_get(void);

int crypto_ssl_connect(SSL *ssl, int *err);
int crypto_ssl_accept(SSL *ssl, int *err);
uint32_t crypto_gen_rand_token(void);

#ifdef __cplusplus
}
#endif

#endif